package cc.rengu.igas.channel.cups.core.packswitch;

import cc.rengu.igas.channel.cups.common.constant.CupsParamConstant;
import cc.rengu.igas.channel.cups.common.constant.CupsTreeNodeConstant;
import cc.rengu.igas.channel.cups.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.cups.core.model.CupsFieldRspBean;
import cc.rengu.igas.channel.cups.core.realize.CupsMacService;
import cc.rengu.igas.channel.cups.core.realize.impl.CupsMacServiceImpl;
import cc.rengu.igas.share.facade.bean.CupsField;
import cc.rengu.igas.share.facade.bean.CupsFieldBean;
import cc.rengu.jradp.mods.trmsg.iso8583.MacUtil;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.KeyInfoMapper;
import cc.rengu.oltp.service.common.dao.SecPlanInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.KeyInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.SecPlanInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.KeyInfo;
import cc.rengu.oltp.service.common.entity.SecPlanInfo;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.cache.UnifiedCache;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Optional;

import static cc.rengu.igas.channel.cups.common.constant.CupsParamConstant.CUPS_INSTIDCODE_FILL_LEN;

/**
 * 银联CUPS发卡侧流入流出处理
 *
 * @author app
 */
public class CupsServerPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {

    /**
     * 请求报文转换后对整个报文TotalMsgLen重新填写值
     */
    @Override
    public byte[] afterOutgoPackSwitch(byte[] arg0) {
        String strTotalLen = String.format("%04d", arg0.length);
        byte[] byteTotalLen = strTotalLen.getBytes(StandardCharsets.UTF_8);

        System.arraycopy(byteTotalLen, 0, arg0, 2, 4);

        //调换原id和目的id的值
        byte[] origSourceId = new byte[11];
        byte[] origDestId = new byte[11];
        System.arraycopy(arg0, 17, origSourceId, 0, CUPS_INSTIDCODE_FILL_LEN);
        System.arraycopy(arg0, 6, origDestId, 0, CUPS_INSTIDCODE_FILL_LEN);
        System.arraycopy(origDestId, 0, arg0, 17, CUPS_INSTIDCODE_FILL_LEN);
        System.arraycopy(origSourceId, 0, arg0, 6, CUPS_INSTIDCODE_FILL_LEN);
        return arg0;
    }

    @Override
    public int beforeOutgoPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        byte[] macBlockRsp;
        MacUtil commonMac;
        /*设置消息类型第三位为原数值+1*/
        String msgType = xmlTreeUtil.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MSG_TYPE);
        String procCode = xmlTreeUtil.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_TXN_PROC_CODE);
        if (msgType != null) {
            char[] bmsgType = msgType.toCharArray();
            bmsgType[2]++;
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MSG_TYPE, new String(bmsgType));
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_MSG_TYPE, new String(bmsgType));
        } else {
            //未知CUPS交易类型
            rglog.error("未知CUPS交易类型");
            return -1;
        }
        String respCode = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.RESP_CODE);
        if (respCode != null && RespCodeEnum.TRANS_SUCCESS.getRespCode().equals(respCode)) {
            respCode = "00";
        } else if (respCode == null || respCode.length() != 2) {
            /*联系发卡行*/
            respCode = "01";
        }
        xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_CODE, respCode);
        xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_RSP_CODE, respCode);
        if (msgType.startsWith("08")) {
            /*管理类交易*/
            commonMac = (MacUtil) UnifiedCache.get(CupsParamConstant.CUPS_8583_MAC_CACHE_NAME,
                    CupsParamConstant.CUPS_8583_MAC_FILE +
                            CupsParamConstant.CUPS_8583_MAC_TYPE_KEY);
            macBlockRsp = commonMac.genMacBlock(CupsParamConstant.CUPS_8583_MAC_TYPE_KEY);
        } else if (procCode != null) {
            if (procCode.startsWith("4") || procCode.startsWith("62")) {
                /*转账类交易，包括非指定圈存*/
                commonMac = (MacUtil) UnifiedCache.get(CupsParamConstant.CUPS_8583_MAC_CACHE_NAME,
                        CupsParamConstant.CUPS_8583_MAC_FILE +
                                CupsParamConstant.CUPS_8583_MAC_TYPE_TA);
                macBlockRsp = commonMac.genMacBlock(CupsParamConstant.CUPS_8583_MAC_TYPE_TA);
            } else {
                /* 一般交易 */
                commonMac = (MacUtil) UnifiedCache.get(CupsParamConstant.CUPS_8583_MAC_CACHE_NAME,
                        CupsParamConstant.CUPS_8583_MAC_FILE +
                                CupsParamConstant.CUPS_8583_MAC_TYPE_COMMON);
                macBlockRsp = commonMac.genMacBlock(CupsParamConstant.CUPS_8583_MAC_TYPE_COMMON);
            }
        } else {
            /* 一般交易 */
            commonMac = (MacUtil) UnifiedCache.get(CupsParamConstant.CUPS_8583_MAC_CACHE_NAME,
                    CupsParamConstant.CUPS_8583_MAC_FILE +
                            CupsParamConstant.CUPS_8583_MAC_TYPE_COMMON);
            macBlockRsp = commonMac.genMacBlock(CupsParamConstant.CUPS_8583_MAC_TYPE_COMMON);
        }
        CupsMacService cupsMacService = new CupsMacServiceImpl();
        KeyInfo keyInfo = (KeyInfo) xmlTreeUtil.getXmlTreeObjectValue(CupsTreeNodeConstant.CUPS_MAC_KEY_INFO, KeyInfo.class);
        if (keyInfo == null) {
            // TODO 告警；正常情况不会是null,除非没维护
            //xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_CODE,"01");
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_MAC_VAL, "3030303030303030");
        } else {
            String mac = cupsMacService.genMacString(keyInfo, new String(macBlockRsp, CupsParamConstant.GB18030));
            if (mac != null) {
                xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_MAC_VAL, ByteUtil.bytesToHexString(mac.substring(0, 8).getBytes(CupsParamConstant.GB18030)));
            } else {
                //TODO 告警
                //xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_CODE,"01");
                xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_MAC_VAL, "3030303030303030");
            }
        }
        return 0;
    }

    @Override
    public int afterInComPackSwitch() throws Exception {
        RgLogger rglog = RgLog.getLogger(this.getClass().getName());
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        if (xmlTreeUtil.isExist(CupsTreeNodeConstant.CUPS_ORIG_DATA_ELEMTS)) {
            String origData = xmlTreeUtil.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_ORIG_DATA_ELEMTS);
            if (origData != null && origData.length() > 20) {
                xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MACBLOCK_ORIG_DATA_ELEMTS, origData.substring(0, 20));
            } else {
                xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MACBLOCK_ORIG_DATA_ELEMTS, origData);
            }
        }

        CupsFieldBean cupsFieldBean = new CupsFieldBean();
        ConvertUtil.convertOutput(cupsFieldBean);
        CupsField cupsFieldRsp = new CupsField();
        BeanUtil.beanCopy(cupsFieldBean.getCupsField(), cupsFieldRsp);
        CupsFieldRspBean cupsFieldRspBeanBean = new CupsFieldRspBean();
        cupsFieldRspBeanBean.setCupsFieldRsp(cupsFieldRsp);
        ConvertUtil.convertInput(cupsFieldRspBeanBean);

        /* 获取通道配置信息 */
        String instId = "";
        String txnNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_NUM);
        if (xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID) == null) {
            instId = AppParamConstant.DEFAULT_INSTID;
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.INST_ID, instId);
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID, ChannelEnum.CUPS.getChannelType());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.CHANNEL_ID, ChannelEnum.CUPS.getChannelType());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.MSG_SRC_ID, ChannelEnum.CUPS.getChannelType());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.BIZ_TYPE, AppParamConstant.DEFAULT_BIZ_TYPE);
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_DATE_TIME, cupsFieldBean.getCupsField().getTransDateTime());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRACE_NO, "CUPS" + cupsFieldBean.getCupsField().getTransDateTime() + RandomUtil.getRandomInt());
        } else {
            instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
        }

        String dstChannelKey = instId + ChannelEnum.CUPS.getChannelType();
        DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelKey), DstChannelInfo.class);
        if (null == dstChannelInfo) {
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, ChannelEnum.CUPS.getChannelType());
        }
        if (null == dstChannelInfo || !dstChannelInfo.getDstChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
            //银联发起的打开机构不校验通道状态
            if (!"M00CU001".equals(txnNum) && !"M00CU008".equals(txnNum) && !"M00CU010".equals(txnNum)) {
                rglog.error("支付渠道<{}-{}>未配置或已停用！", ChannelEnum.CUPS.getChannelType(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
                throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
            }
        }

        xmlTreeUtil.setXmlTreeObjectValue(CupsTreeNodeConstant.SRC_CHANNEL_INFO, dstChannelInfo);
        /* 根据通道安全计划获取安全计划 */
        SecPlanInfoMapper secPlanInfoMapper = new SecPlanInfoMapperImpl();
        List<SecPlanInfo> secPlanInfoList = secPlanInfoMapper.selectSecPlanInfoBySecPlanId(dstChannelInfo.getInstId(), dstChannelInfo.getSecPlanId());
        if (null != secPlanInfoList && !secPlanInfoList.isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.SEC_PLAN_INFO_LIST, JSON.toJSONString(secPlanInfoList));
            /* mac密钥 */
            Optional<SecPlanInfo> secPlanInfoOpt = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(CupsParamConstant.MAC_KEY_TYPE)).findFirst();
            if (secPlanInfoOpt.isPresent()) {
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo keyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(instId + secPlanInfoOpt.get().getSecPlanId() + secPlanInfoOpt.get().getSecPlanType());
                if (keyInfo == null) {
                    throw new BizException(RespCodeEnum.GET_KEY_INFO_ERROR.getRespCode(), RespCodeEnum.GET_KEY_INFO_ERROR.getRespDesc());
                }
                xmlTreeUtil.setXmlTreeObjectValue(CupsTreeNodeConstant.CUPS_MAC_KEY_INFO, keyInfo);
            }
            /*pin密钥*/
            Optional<SecPlanInfo> secPlanInfoOptPin = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(CupsParamConstant.PIN_KEY_TYPE)).findFirst();
            if (secPlanInfoOptPin.isPresent()) {
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo pinKeyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(instId + secPlanInfoOptPin.get().getSecPlanId() + secPlanInfoOptPin.get().getSecPlanType());
                if (pinKeyInfo != null) {
                    xmlTreeUtil.setXmlTreeObjectValue(CupsTreeNodeConstant.CUPS_PIN_KEY_INFO, pinKeyInfo);
                    //throw new BizException(RespCodeEnum.GET_KEY_INFO_ERROR.getRespCode(),RespCodeEnum.GET_KEY_INFO_ERROR.getRespDesc());
                }
            }
            /*主密钥*/
            Optional<SecPlanInfo> secPlanInfoOptLmk = secPlanInfoList.stream().filter(item -> item.getSecPlanType().equals(CupsParamConstant.TMK_KEY_TYPE)).findFirst();
            if (secPlanInfoOptPin.isPresent()) {
                KeyInfoMapper keyInfoMapper = new KeyInfoMapperImpl();
                KeyInfo lmkKeyInfo = keyInfoMapper.selectKeyInfoByPrimaryKey(instId + secPlanInfoOptLmk.get().getSecPlanId() + secPlanInfoOptLmk.get().getSecPlanType());
                if (lmkKeyInfo != null) {
                    xmlTreeUtil.setXmlTreeObjectValue(CupsTreeNodeConstant.CUPS_LMK_KEY_INFO, lmkKeyInfo);
                    //throw new BizException(RespCodeEnum.GET_KEY_INFO_ERROR.getRespCode(),RespCodeEnum.GET_KEY_INFO_ERROR.getRespDesc());
                }
            }
        }
        return 0;
    }

    /**
     * 报文转换之前确定CUPS应答报文为正确报文或者是错误报文
     * 根据报文头中的拒绝码确定：
     * 若拒绝码不为00000，则该报文为错误报文，存在一个新增报文头与原始的请求报文；
     * 并且可以根据拒绝码确定请求报文的具体错误
     * 否则为正确报文，可以使用配置解析
     */
    @Override
    public byte[] beforeInComPackSwitch(byte[] arg0) {

        return arg0;
    }
}
